#ifndef SWEGL_VECTOR2_H
#define SWEGL_VECTOR2_H

namespace swegl
{

template<typename T> class Vector2
{
public:
	// default contructor, do not initialize components
	Vector2();
	Vector2(T x, T y);
	Vector2(const Vector2 &rhs);
	
	Vector2 &set(T x, T y);
	Vector2 &operator = (const Vector2 &rhs);
	Vector2 operator - () const;
	
	void operator += (const Vector2 &rhs);
	void operator -= (const Vector2 &rhs);
	void operator *= (const Vector2 &rhs);
	void operator *= (T s);
	void operator /= (const Vector2 &rhs);
	void operator /= (T s);
	
	Vector2 operator + (const Vector2 &rhs) const;
	Vector2 operator - (const Vector2 &rhs) const;
	T operator * (const Vector2 &rhs) const;
	Vector2 operator * (T s) const;
	Vector2 operator / (T s) const;
	
	bool operator == (const Vector2 &rhs) const;
	bool operator != (const Vector2 &rhs) const;

	T length() const;
	T sqrLength() const;
	
	// clamp v to the range [min..max]
	static Vector2 clamp(const Vector2 &v, const Vector2 &min, const Vector2 &max);
	
	T x;
	T y;
};

template <typename T> Vector2<T> operator * (T s, const Vector2<T> rhs);

typedef Vector2<float> Vec2;
typedef Vector2<uint> Vec2u;

template<typename T> inline Vector2<T>::Vector2()
{
}

template<typename T> inline Vector2<T>::Vector2(T x, T y) : x(x), y(y)
{
}

template<typename T> inline Vector2<T>::Vector2(const Vector2 &rhs) : x(rhs.x), y(rhs.y)
{
}

template<typename T> inline Vector2<T> &Vector2<T>::set(T x, T y)
{
	this->x = x;
	this->y = y;
	return *this;
}

template<typename T> inline Vector2<T> &Vector2<T>::operator = (const Vector2 &rhs)
{
	this->x = rhs.x;
	this->y = rhs.y;
	return *this;
}

template<typename T> inline Vector2<T> Vector2<T>::operator - () const
{
	return Vector2(- this->x, - this->y);
}
	
template<typename T> inline void Vector2<T>::operator += (const Vector2 &rhs)
{
	this->x += rhs.x;
	this->y += rhs.y;
}

template<typename T> inline void Vector2<T>::operator -= (const Vector2 &rhs)
{
	this->x -= rhs.x;
	this->y -= rhs.y;
}

template<typename T> inline void Vector2<T>::operator *= (const Vector2 &rhs)
{
	this->x *= rhs.x;
	this->y *= rhs.y;
}

template<typename T> inline void Vector2<T>::operator *= (T s)
{
	this->x *= s;
	this->y *= s;
}

template<typename T> inline void Vector2<T>::operator /= (const Vector2 &rhs)
{
	this->x /= rhs.x;
	this->y /= rhs.y;
}

template<typename T> inline void Vector2<T>::operator /= (T s)
{
	this->x /= s;
	this->y /= s;
}

template<typename T> inline Vector2<T> Vector2<T>::operator + (const Vector2 &rhs) const
{
	return Vector2(this->x + rhs.x, this->y + rhs.y);
}

template<typename T> inline Vector2<T> Vector2<T>::operator - (const Vector2 &rhs) const
{
	return Vector2(this->x - rhs.x, this->y - rhs.y);
}

template<typename T> inline T Vector2<T>::operator * (const Vector2 &rhs) const
{
	return this->x * rhs.x + this->y * rhs.y;
}

template<typename T> inline Vector2<T> Vector2<T>::operator * (T s) const
{
	return Vector2(this->x * s, this->y * s);
}

template<typename T> inline Vector2<T> Vector2<T>::operator / (T s) const
{
	return Vector2(this->x / s, this->y / s);
}

template<typename T> inline bool Vector2<T>::operator == (const Vector2 &rhs) const
{
	return this->x == rhs.x && this->y == rhs.y;
}

template<typename T> inline bool Vector2<T>::operator != (const Vector2 &rhs) const
{
	return this->x != rhs.x || this->y != rhs.y;
}

template<typename T> inline T Vector2<T>::length() const
{
	return sqrt(x * x + y * y);
}

template<typename T> inline T Vector2<T>::sqrLength() const
{
	return x * x + y * y;
}

template<typename T> inline Vector2<T> Vector2<T>::clamp(const Vector2 &v, const Vector2 &min, const Vector2 &max)
{
	return Vector2(clamp(v.x, min.x, max.x), clamp(v.y, min.y, max.y));
}

template <typename T> Vector2<T> operator * (T s, const Vector2<T> rhs)
{
	return rhs * s;
}

}

#endif
